package com.letcode.study.juc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 三种方式的等待和唤醒
 * @Date 2022/11/13 23:29:19
 * @Author luopeng
 */
public class LockSupportDemo {
    private static final Object object = new Object();
    private static final ReentrantLock lock = new ReentrantLock();
    private static final Condition condition = lock.newCondition();
    public static void main(String[] args) {
        lockSupportDemo();
//        conditionAwaitSignal();
//        synchronizedWaitNotify();
    }

    /**
     * 必须配合ReentrantLock使用
     * 必须先等待后唤醒
     */
    private static void conditionAwaitSignal() {
        new Thread(() -> {
            lock.lock();
            try {
                try {
                    System.out.println(Thread.currentThread().getName() + "===============进入线程A");
                    condition.await();
                    System.out.println(Thread.currentThread().getName() + "================线程A被唤醒");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                lock.unlock();
            }
        },"A").start();

        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
        new Thread(() -> {
            lock.lock();
            try {
                condition.signal();
                System.out.println(Thread.currentThread().getName() + "================通知");
            } finally {
                lock.unlock();
            }
        },"B").start();
    }

    /**
     * 必须配合synchronized使用，否则报错
     * 必须先等待后唤醒
     */
    private static void synchronizedWaitNotify() {
        new Thread(() -> {
            synchronized (object) {
                try {
                    System.out.println(Thread.currentThread().getName() + "===============进入线程A");
                    object.wait();
                    System.out.println(Thread.currentThread().getName() + "================线程A被唤醒");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

        new Thread(() -> {
            synchronized (object) {
                object.notify();
                System.out.println(Thread.currentThread().getName() + "================通知");
            }
        },"B").start();
    }

    /**
     * 单独使用无限制，使用许可证的方式来认定当前是否被阻塞，许可证只能发放一个，同时调用多次unpark也只能发放1个
     * 等待与唤醒先后无限制
     */
    private static void lockSupportDemo() {
        Thread a = new Thread(() -> {
            try { TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName() + "===============进入线程A");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + "================线程A被唤醒");
        }, "A");
        a.start();

        Thread b = new Thread(() -> {
            LockSupport.unpark(a);
            System.out.println(Thread.currentThread().getName() + "==============通知");
        }, "B");
        b.start();
    }

}
